﻿using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

namespace Simulation.Framework.Editor
{
    /// <summary>
    /// 页面代码解析 - 仅 UI 控件
    /// </summary>
    public class PanelCodeResolver
    {
        private const string tabStr = "    ";

        private PanelCodeData data;

        private CodeCompileUnit codeCompileUnit;
        private CodeNamespace codeNamespace;
        private CodeTypeDeclaration declaration;
        private CodeRegionDirective controlRegionStart;
        private CodeRegionDirective regionEnd;
        private CodeMemberMethod initMember;
        private CodeMemberMethod clearMember;

        // init 方法 实例化部分
        private CodeStatementCollection initMethodInitCollection = new CodeStatementCollection();
        // init 方法 按钮部分
        private CodeStatementCollection initMethodButtonCollection = new CodeStatementCollection();
        // clear 方法 按钮部分
        private CodeStatementCollection clearMethodButtonCollection = new CodeStatementCollection();
        // clear 方法 置空引用部分
        private CodeStatementCollection clearMethodFieldCollection = new CodeStatementCollection();
        // 字段的路径
        private Dictionary<string, string> fieldPath = new Dictionary<string, string>();

        // 属性行 代码
        private List<CodeMemberField> codeMemberFieldCollection = new List<CodeMemberField>();

        public PanelCodeResolver() { }

        public PanelCodeResolver(PanelCodeData data)
        {
            this.data = data;
        }

        /// <summary>
        /// 是否是 UI 类型，冒泡检测
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsBaseTypeUIControl(Type type)
        {
            if (type == null)
                return false;

            if (IsUIControl(type))
                return true;

            // 向上查找 count 次
            int count = 4;
            for (int i = 0; i < count; i++)
            {
                type = type.BaseType;
                if (type == null)
                    return false;

                if (IsUIControl(type))
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 是否是 UI 类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsUIControl(Type type)
        {
            if (type == null)
                return false;

            // 命名空间
            List<string> nameSpaces = new List<string>();
            nameSpaces.Add("UnityEngine.UI");
            if (nameSpaces.Contains(type.Namespace))
                return true;

            // 程序集
            List<Assembly> assemblies = new List<Assembly>();
            assemblies.Add(typeof(Image).Assembly);
            assemblies.Add(typeof(CanvasRenderer).Assembly);
            Assembly assembly = typeof(Image).Assembly;
            if (assemblies.Contains(type.Assembly))
                return true;

            // 特殊类型
            List<Type> specialType = new List<Type>();
            specialType.Add(typeof(RectTransform));
            specialType.Add(typeof(CanvasRenderer));
            if (specialType.Contains(type))
                return true;

            // 否则为 false
            return false;
        }

        /// <summary>
        /// 新建主文件
        /// </summary>
        /// <param name="destFile"></param>
        /// <param name="sName"></param>
        /// <param name="className"></param>
        public void CreateMainClass(string destFile, string sName, string className)
        {
            if (File.Exists(destFile))
                throw new Exception("文件已存在");

            CodeCompileUnit codeCompileUnit = CreateCodeCompileUnit(sName, className);

            // 命名空间
            CodeNamespace nameSpace = codeCompileUnit.Namespaces[0];

            // 类
            CodeTypeDeclaration codeType = nameSpace.Types[0];

            // region - override
            CodeRegionDirective overrideRegionStart = new CodeRegionDirective(CodeRegionMode.Start, "override");
            CodeRegionDirective overrideRegionEnd = new CodeRegionDirective(CodeRegionMode.End, "");

            // 方法
            CodeMemberMethod initMember = new CodeMemberMethod();
            initMember.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            initMember.Name = "Init";
            initMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "InitComponent();"));
            initMember.Parameters.Add(new CodeParameterDeclarationExpression("params object[] ", "data"));


            CodeMemberMethod clearMember = new CodeMemberMethod();
            clearMember.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            clearMember.Name = "Clear";
            clearMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "ClearComponent();"));

            CodeMemberMethod openMember = new CodeMemberMethod();
            openMember.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            openMember.Name = "Open";
            openMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "gameObject.SetActive(true);"));
            
            CodeMemberMethod closeMember = new CodeMemberMethod();
            closeMember.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            closeMember.Name = "Close";
            closeMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "gameObject.SetActive(false);"));

            initMember.StartDirectives.Add(overrideRegionStart);
            closeMember.EndDirectives.Add(overrideRegionEnd);

            codeType.Members.Add(initMember);
            codeType.Members.Add(clearMember);
            codeType.Members.Add(openMember);
            codeType.Members.Add(closeMember);

            WriteScript(codeCompileUnit, destFile, sName, className);
        }

        /// <summary>
        /// 新建 UI 控件脚本
        /// </summary>
        /// <param name="destFile"></param>
        /// <param name="sName"></param>
        /// <param name="className"></param>
        public void CreateExtendClass(string destFile, string sName, string className)
        {
            string folder = Path.GetDirectoryName(destFile);
            string fileName = Path.GetFileNameWithoutExtension(destFile);
            string extendPath = folder + "/" + fileName + "_extend.cs";

            if (File.Exists(extendPath))
                throw new Exception("文件已存在:" + extendPath);

            CodeCompileUnit codeCompileUnit = CreateCodeCompileUnit(sName, className);

            // 命名空间
            CodeNamespace nameSpace = codeCompileUnit.Namespaces[0];

            // 类
            CodeTypeDeclaration codeType = nameSpace.Types[0];

            // region - override
            CodeRegionDirective controlRegionStart = new CodeRegionDirective(CodeRegionMode.Start, "control");
            CodeRegionDirective controlRegionEnd = new CodeRegionDirective(CodeRegionMode.End, "");

            // 方法
            CodeMemberMethod initMember = new CodeMemberMethod();
            initMember.Attributes = MemberAttributes.Private;
            initMember.Name = "InitComponent";

            CodeMemberMethod clearMember = new CodeMemberMethod();
            clearMember.Attributes = MemberAttributes.Private;
            clearMember.Name = "ClearComponent";

            initMember.StartDirectives.Add(controlRegionStart);
            clearMember.EndDirectives.Add(controlRegionEnd);

            codeType.Members.Add(initMember);
            codeType.Members.Add(clearMember);

            WriteScript(codeCompileUnit, extendPath, sName, className);
        }

        /// <summary>
        /// 获取所有 UI 属性
        /// </summary>
        /// <returns></returns>
        public List<PropertyInfo> GetUIFields()
        {
            Type selectedPanel = data.mainScript.GetClass();
            if (selectedPanel == null)
                throw new Exception("获取页面类型失败");

            List<PropertyInfo> names = new List<PropertyInfo>();
            BindingFlags flags =
                BindingFlags.DeclaredOnly |
                BindingFlags.Public |
                BindingFlags.GetProperty |
                BindingFlags.Instance;

            PropertyInfo[] infos = selectedPanel.GetProperties(flags);

            for (int i = 0; i < infos.Length; i++)
            {
                PropertyInfo info = infos[i];
                Type propertyType = info.PropertyType;
                // 如果是 ui 控件
                if (IsBaseTypeUIControl(propertyType))
                {
                    names.Add(info);
                }
            }
            return names;
        }

        /// <summary>
        /// 是否包含
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        public bool ContainsComponent(Component component)
        {
            if (string.IsNullOrEmpty(data.mainPath)) return false;
            string value = GetFieldName(component);
            List<PropertyInfo> propertys = GetUIFields();
            return propertys.FindIndex(0, v => v.Name == value) != -1;
        }

        /// <summary>
        /// 插入属性
        /// </summary>
        /// <param name="component"></param>
        public void InsertField(Component component)
        {
            // 如果不是 UI 字段，返回
            if (!IsBaseTypeUIControl(component.GetType()))
                return;

            Type fieldType = component.GetType();
            string name = GetFieldName(component);

            fieldPath.Add(name,GetComponentPath(component));

            InsertField(name, fieldType);
            InsertMethodStatement(name, fieldType);
            UpdateMethodStatement(codeCompileUnit);
        }

        /// <summary>
        /// 删除属性
        /// </summary>
        /// <param name="component"></param>
        public void DeleteField(Component component)
        {
            // 如果不是 UI 字段，返回
            if (!IsBaseTypeUIControl(component.GetType()))
                return;
            Type fieldType = component.GetType();
            string name = GetFieldName(component);
            // 移除字段
            RemoveFiled(name);
            // 移除字段相关代码
            RemoveMethodStatement(name, fieldType);
            // 移除缓存
            if (fieldPath.ContainsKey(name))
                fieldPath.Remove(name);

            UpdateMethodStatement(codeCompileUnit);
        }

        public CodeCompileUnit Parse()
        {
            Type type = data.mainScript.GetClass();
            string code = data.mainScript.text;
            string extendPath = data.extendPath;

            string[] codeAllLines = code.Split(new string[] { "\n", "\r" }, StringSplitOptions.None);

            if (codeAllLines == null || codeAllLines.Length == 0)
                throw new Exception("指定代码为 null");

            codeCompileUnit = CreateCodeCompileUnit(type.Namespace, type.Name);
            codeNamespace = codeCompileUnit.Namespaces[0];
            declaration = codeNamespace.Types[0];

            // region - override
            controlRegionStart = new CodeRegionDirective(CodeRegionMode.Start, "control");
            regionEnd = new CodeRegionDirective(CodeRegionMode.End, "");

            // 方法
            initMember = new CodeMemberMethod();
            initMember.Attributes = MemberAttributes.Private;
            initMember.Name = "InitComponent";

            clearMember = new CodeMemberMethod();
            clearMember.Attributes = MemberAttributes.Private;
            clearMember.Name = "ClearComponent";

            // 字段-属性
            List<PropertyInfo> propertyInfos = GetUIFields();

            initMethodInitCollection?.Clear();
            initMethodButtonCollection?.Clear();
            clearMethodButtonCollection?.Clear();
            clearMethodFieldCollection?.Clear();

            initMethodInitCollection = new CodeStatementCollection();
            initMethodButtonCollection = new CodeStatementCollection();
            clearMethodButtonCollection = new CodeStatementCollection();
            clearMethodFieldCollection = new CodeStatementCollection();

            fieldPath = new Dictionary<string, string>();

            for (int i = 0; i < propertyInfos.Count; i++)
            {
                PropertyInfo propertyInfo = propertyInfos[i];

                // 剔除不在当前文件中的属性
                if (!IsPropertyInCurrScripts(propertyInfo))
                    continue;

                // 更新字典
                string str = FindPropertyInstanceCode(propertyInfo.Name, propertyInfo.PropertyType);
                if (!string.IsNullOrEmpty(str))
                {
                    int start = str.IndexOf("\"") + 1;
                    int end = str.IndexOf("\"", start);
                    string path = str.Substring(start, end - start);
                    fieldPath[propertyInfo.Name] = path;
                }

                // 字段 - 仿属性
                InsertField(propertyInfo.Name, propertyInfo.PropertyType);
                // 方法
                InsertMethodStatement(propertyInfo.Name, propertyInfo.PropertyType);
            }


            // 关联
            initMember.StartDirectives.Add(controlRegionStart);
            clearMember.EndDirectives.Add(regionEnd);

            declaration.Members.Add(initMember);
            declaration.Members.Add(clearMember);

            UpdateMethodStatement(codeCompileUnit);

            return codeCompileUnit;
        }

        #region field

        public void InsertField(string name, Type type)
        {
            CodeMemberField codeMemberField = new CodeMemberField();
            codeMemberField.Name = name + "{get;private set;}";
            codeMemberField.Type = new CodeTypeReference(type);
            codeMemberField.Attributes = MemberAttributes.Public;
            declaration.Members.Add(codeMemberField);
        }

        public void RemoveFiled(string name)
        {
            name += "{get;private set;}";
            for (int i = 0; i < declaration.Members.Count; i++)
            {
                CodeMemberField codeMemberField = declaration.Members[i] as CodeMemberField;
                if (codeMemberField != null && codeMemberField.Name == name)
                    declaration.Members.Remove(codeMemberField);
            }
        }

        #endregion

        #region method statement

        // 更新方法
        private void UpdateMethodStatement(CodeCompileUnit codeCompileUnit)
        {
            initMember.Statements.Clear();
            initMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "// init"));
            initMember.Statements.AddRange(initMethodInitCollection);
            initMember.Statements.Add(new CodeSnippetStatement("\r\n\r\n"));
            initMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "// button"));
            initMember.Statements.AddRange(initMethodButtonCollection);

            clearMember.Statements.Clear();
            clearMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "// button"));
            clearMember.Statements.AddRange(clearMethodButtonCollection);
            clearMember.Statements.Add(new CodeSnippetStatement("\r\n\r\n"));
            clearMember.Statements.Add(new CodeSnippetStatement(tabStr + tabStr + tabStr + "// clear"));
            clearMember.Statements.AddRange(clearMethodFieldCollection);
        }

        //=========================== Insert 方法 =========================//

        // 插入一个属性的同时，更新方法
        private void InsertMethodStatement(string name, Type type)
        {
            // init
            InsertInitMethodInitStatement(name,type, initMethodInitCollection);
            // button - add
            InsertInitMethodButtonStatement(name, type, initMethodButtonCollection);
            // clear
            InsertClearMethodFieldStatement(name, type, clearMethodFieldCollection);
            // button - remove
            InsertClearMethodButtonStatement(name, type, clearMethodButtonCollection);
        }

        // 实例
        private void InsertInitMethodInitStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            string path = fieldPath.ContainsKey(name) ? fieldPath[name] : string.Empty;
            string findCode = string.Format("transform.Find(\"{0}\")", path);
            string initCode = string.Format("{0} = {1}.GetComponent<{2}>();", name, findCode, type);
            initCode = tabStr + tabStr + tabStr + initCode;
            codeStatementCollection.Add(new CodeSnippetStatement(initCode));
        }

        // 添加事件
        private void InsertInitMethodButtonStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            // button
            if (type == typeof(Button))
            {
                string removeCode = string.Format("{0}.onClick.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "Clicked";
                string addCode = string.Format("{0}.onClick.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                codeStatementCollection.Add(new CodeSnippetStatement(addCode));
                InsertMethod(method);
            }
            // toggle
            else if (type == typeof(Toggle))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                codeStatementCollection.Add(new CodeSnippetStatement(addCode));
                InsertMethod(method,typeof(bool));
            }
            // scroll
            else if (type == typeof(ScrollRect))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                codeStatementCollection.Add(new CodeSnippetStatement(addCode));
                InsertMethod(method, typeof(Vector2));
            }
            // slider
            else if (type == typeof(Slider))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                codeStatementCollection.Add(new CodeSnippetStatement(addCode));
                InsertMethod(method, typeof(float));
            }
        }

        // 移除事件
        private void InsertClearMethodButtonStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            // button
            if (type == typeof(Button))
            {
                string removeCode = string.Format("{0}?.onClick.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));
            }
            // toggle
            else if (type == typeof(Toggle))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));
            }
            // scroll
            else if (type == typeof(ScrollRect))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));
            }
            // slider
            else if (type == typeof(Slider))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                codeStatementCollection.Add(new CodeSnippetStatement(removeCode));
            }
        }

        // 置空
        private void InsertClearMethodFieldStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            string removeCode = string.Format("{0} = null;", name);
            removeCode = tabStr + tabStr + tabStr + removeCode;
            codeStatementCollection.Add(new CodeSnippetStatement(removeCode));
        }

        //=========================== Remove 方法 =========================//

        private void RemoveMethodStatement(string name, Type type)
        {
            // init
            RemoveInitMethodInitStatement(name, type, initMethodInitCollection);
            // button - add
            RemoveInitMethodButtonStatement(name, type, initMethodButtonCollection);
            // clear
            RemoveClearMethodFieldStatement(name, type, clearMethodFieldCollection);
            // button - remove
            RemoveClearMethodButtonStatement(name, type, clearMethodButtonCollection);
        }

        // 实例
        private void RemoveInitMethodInitStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            string path = fieldPath.ContainsKey(name) ? fieldPath[name] : string.Empty;
            string findCode = string.Format("transform.Find(\"{0}\")", path);
            string initCode = string.Format("{0} = {1}.GetComponent<{2}>();", name, findCode, type);
            initCode = tabStr + tabStr + tabStr + initCode;
            RemoveStatementHelper(initCode,codeStatementCollection);
        }

        // 添加事件
        private void RemoveInitMethodButtonStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            // button
            if (type == typeof(Button))
            {
                string removeCode = string.Format("{0}.onClick.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "Clicked";
                string addCode = string.Format("{0}.onClick.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                RemoveStatementHelper(addCode, codeStatementCollection);
            }
            // toggle
            else if (type == typeof(Toggle))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                RemoveStatementHelper(addCode, codeStatementCollection);
            }
            // scroll
            else if (type == typeof(ScrollRect))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                RemoveStatementHelper(addCode, codeStatementCollection);
            }
            // slider
            else if (type == typeof(Slider))
            {
                string removeCode = string.Format("{0}.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);

                // 首字母大写
                string first = name[0].ToString().ToUpper();
                string newName = first + name.Substring(1);
                string method = "On" + newName + "ValueChanged";
                string addCode = string.Format("{0}.onValueChanged.AddListener({1});", name, method);
                addCode = tabStr + tabStr + tabStr + addCode;
                RemoveStatementHelper(addCode, codeStatementCollection);
            }
        }

        // 移除事件
        private void RemoveClearMethodButtonStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            // button
            if (type == typeof(Button))
            {
                string removeCode = string.Format("{0}?.onClick.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);
            }
            // toggle
            else if (type == typeof(Toggle))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);
            }
            // scroll
            else if (type == typeof(ScrollRect))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);
            }
            // slider
            else if (type == typeof(Slider))
            {
                string removeCode = string.Format("{0}?.onValueChanged.RemoveAllListeners();", name);
                removeCode = tabStr + tabStr + tabStr + removeCode;
                RemoveStatementHelper(removeCode, codeStatementCollection);
            }
        }

        // 置空
        private void RemoveClearMethodFieldStatement(string name, Type type, CodeStatementCollection codeStatementCollection)
        {
            string removeCode = string.Format("{0} = null;", name);
            removeCode = tabStr + tabStr + tabStr + removeCode;
            RemoveStatementHelper(removeCode, codeStatementCollection);
        }

        private void RemoveStatementHelper(string code,CodeStatementCollection codeStatementCollection)
        {
            if (codeStatementCollection == null) return;
            for (int i = 0; i < codeStatementCollection.Count; i++)
            {
                CodeSnippetStatement codeSnippetStatement = codeStatementCollection[i] as CodeSnippetStatement;
                if (code == codeSnippetStatement.Value)
                    codeStatementCollection.Remove(codeSnippetStatement);
            }
        }

        #endregion

        #region method

        private void InsertMethod(string name,params Type[] para)
        {
            Type type = data.mainScript.GetClass();
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;

            // 如果已有方法，且不在当前文件中
            if ((type.GetMethod(name, bindingFlags) != null) && !IsMethodInCurrScripts(name))
                    return;
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = name;
            method.Attributes = MemberAttributes.Private;
            for (int i = 0; i < para.Length; i++)
                method.Parameters.Add(new CodeParameterDeclarationExpression(para[i], "arg" + i));
            declaration.Members.Add(method);
        }

        #endregion

        #region write

        public void WriteScript()
        {
            string path = data.extendPath;
            string sName = codeNamespace.Name;
            string cName = declaration.Name;
            WriteScript(codeCompileUnit, data.extendPath, sName, cName);
        }

        private void WriteScript(CodeCompileUnit codeCompileUnit, string destFile, string sName, string className)
        {
            CSharpCodeProvider codeDomProvider = new CSharpCodeProvider();
            IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter(destFile, false), "    ");
            codeDomProvider.GenerateCodeFromCompileUnit(codeCompileUnit, tw, new CodeGeneratorOptions());
            tw.Close();
            // 格式化
            Format(destFile, sName, className);
            AssetDatabase.Refresh();
        }

        #endregion

        private CodeCompileUnit CreateCodeCompileUnit(string sName, string className)
        {
            if (string.IsNullOrEmpty(sName) || string.IsNullOrEmpty(className))
            {
                Debug.LogError("名字不能为空");
                return null;
            }

            CodeCompileUnit codeCompileUnit = new CodeCompileUnit();

            // 命名空间
            CodeNamespace nameSpace = new CodeNamespace(sName);
            nameSpace.Imports.Add(new CodeNamespaceImport("System.Collections"));
            nameSpace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
            nameSpace.Imports.Add(new CodeNamespaceImport("UnityEngine"));
            nameSpace.Imports.Add(new CodeNamespaceImport("UnityEngine.UI"));
            nameSpace.Imports.Add(new CodeNamespaceImport("UnityEngine.Events"));
            nameSpace.Imports.Add(new CodeNamespaceImport("Simulation.Framework"));

            // 类
            CodeTypeDeclaration codeType = new CodeTypeDeclaration(className);
            codeType.IsClass = true;
            codeType.IsPartial = true;
            codeType.Attributes = MemberAttributes.Public;

            // 继承
            CodeTypeReference codeTypeReference = new CodeTypeReference(typeof(PanelBase));
            codeType.BaseTypes.Add(codeTypeReference);

            nameSpace.Types.Add(codeType);
            codeCompileUnit.Namespaces.Add(nameSpace);

            return codeCompileUnit;
        }

        #region get keys

        /// <summary>
        /// using 行关键字
        /// </summary>
        /// <returns></returns>
        private string[] GetUsingKeys()
        {
            return new string[] { "using ", ";" };
        }

        /// <summary>
        /// 命名空间行关键字
        /// </summary>
        /// <returns></returns>
        private string[] GetNameSpaceKeys(string nameSpace = "")
        {
            nameSpace = string.IsNullOrEmpty(nameSpace) ? data.mainScript.GetClass().Namespace : nameSpace;
            return new string[] { "namespace", nameSpace };
        }

        /// <summary>
        /// 类行关键字
        /// </summary>
        /// <returns></returns>
        private string[] GetClassKeys(string className = "")
        {
            className = string.IsNullOrEmpty(className) ? data.mainScript.GetClass().Name : className;
            return new string[] { "public", "partial", "class", className, ":", "PanelBase" };
        }

        /// <summary>
        /// 属性行关键字
        /// </summary>
        /// <returns></returns>
        private string[] GetPropertyKeys()
        {
            return GetPropertyKeys(null);
        }

        /// <summary>
        /// 指定属性行关键字
        /// </summary>
        /// <returns></returns>
        private string[] GetPropertyKeys(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
                return new string[] { "public", "{", "get", "private", "set", "}", ";" };
            return new string[] { "public", "{", "get", "private", "set", "}", ";", propertyInfo.PropertyType.Name, propertyInfo.Name };
        }

        /// <summary>
        /// InitComponent 行
        /// </summary>
        /// <returns></returns>
        private string[] GetInitMethodKeys()
        {
            return new string[] { "private", "void", "InitComponent", "()" };
        }

        /// <summary>
        /// ClearComponent 行
        /// </summary>
        /// <returns></returns>
        private string[] GetClearMethodKeys()
        {
            return new string[] { "private", "void", "ClearComponent", "()" };
        }

        // 获取对属性实例的代码
        private string[] GetPropertyInstanceKeys(string name, Type type)
        {
            return new string[] { name, "=", "transform", "Find", "GetComponent", type.Name, ";", "." };
        }

        #endregion

        // 格式化
        private void Format(string file, string nameSpace, string className)
        {
            List<string> newCode = new List<string>();
            string[] scripts = File.ReadAllLines(file);
            for (int i = 0; i < scripts.Length; i++)
            {
                string str = scripts[i];

                // 删除注释
                if (str.StartsWith("//") || str.StartsWith("///"))
                    continue;

                // 避免重复空行
                if (string.IsNullOrWhiteSpace(str.Trim()))
                    str = string.Empty;
                if (newCode.Count > 0 && string.IsNullOrEmpty(newCode[newCode.Count - 1]) && string.IsNullOrEmpty(str))
                    continue;

                // 精简对 PanelBase 的调用
                if (ContainsAllStrItem(str, GetClassKeys(className)))
                    str = str.Replace("Simulation.Framework.", "");

                // 属性去除末尾分号
                if (ContainsAllStrItem(str, GetPropertyKeys()) && str.EndsWith(";"))
                    str = str.Remove(str.LastIndexOf(';'));

                // 移动 using 位置
                if (ContainsAllStrItem(str, GetUsingKeys()))
                {
                    newCode.Insert(0, str.Replace(tabStr, ""));
                    continue;
                }

                // 添加代码行
                newCode.Add(str);
            }

            File.WriteAllLines(file, newCode.ToArray(), System.Text.Encoding.UTF8);
        }

        // source 中是否包含 items 中的所有元素
        private bool ContainsAllStrItem(string source, string[] items)
        {
            if (items == null)
                return false;
            for (int i = 0; i < items.Length; i++)
            {
                string item = items[i];
                if (!source.Contains(item))
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 指定属性是否在当前 cs 文件中
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <returns></returns>
        private bool IsPropertyInCurrScripts(PropertyInfo propertyInfo)
        {
            Type type = data.mainScript.GetClass();
            string code = data.extendScript.text;
            string[] codeAllLines = code.Split(new string[] { "\n", "\r" }, StringSplitOptions.None);

            for (int i = 0; i < codeAllLines.Length; i++)
            {
                string str = codeAllLines[i];
                // 属性
                if (ContainsAllStrItem(str, GetPropertyKeys(propertyInfo)))
                    return true;
            }
            return false;
        }

        // 查找对指定属性实例的代码
        private string FindPropertyInstanceCode(string name,Type type)
        {
            string[] keys = GetPropertyInstanceKeys(name,type);
            string code = data.extendScript.text;
            string[] codeAllLines = code.Split(new string[] { "\n", "\r" }, StringSplitOptions.None);
            for (int i = 0; i < codeAllLines.Length; i++)
            {
                string str = codeAllLines[i];
                // 属性
                if (ContainsAllStrItem(str, keys))
                    return str;
            }
            return string.Empty;
        }

        /// <summary>
        /// 指定方法是否在当前 cs 文件中
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        private bool IsMethodInCurrScripts(string methodName)
        {
            string[] keys = new string[] { methodName, "void" };

            string code = data.extendScript.text;
            string[] codeAllLines = code.Split(new string[] { "\n","\r" }, StringSplitOptions.None);
            for (int i = 0; i < codeAllLines.Length; i++)
            {
                string str = codeAllLines[i];
                // 属性
                if (ContainsAllStrItem(str, keys))
                    return true;
            }
            return false;
        }

        private string GetFieldName(Component component)
        {
            return component.name + component.GetType().Name;
        }

        // 获取组件的路径
        private string GetComponentPath(Component component,string path = "")
        {
            path = component.transform.GetRoute();
            path = path.Substring(path.IndexOf('/') + 1);
            return path;
        }
    }
}